import json
import math
from datetime import datetime
from vulcanus.log.log import LOGGER
from vulcanus.restful.resp import state
from zeus.operation_service.app.core.framework.task.task_result.task_result_detail import TaskResultDetail
from zeus.operation_service.app.core.framework.common.result_code import TaskResultCode, ItemResultCode
from zeus.operation_service.app.proxy.task import TaskProxy
from zeus.operation_service.app.proxy.host import HostProxy
from zeus.operation_service.app.proxy.asset import AssetProxy
from vulcanus.restful.resp.state import SUCCEED


class HealthCheckResultDetail(TaskResultDetail):

    def get_items_detail(self, data):
        node_index = data['node_index']
        case_index = data['case_index']
        host_items_result = self.generate_items_result(node_index, case_index)
        return state.SUCCEED, host_items_result

    def update_progress(self, data):
        # 1. 批量添加Health_check_result_items
        self.batch_add_health_check_results(data, self.task)
        # 2. 修改任务进度
        task_total = self.task.task_total
        healthcheckresultitem_set = AssetProxy().get_result_item_by_task_id(self.task.task_id)
        task_result_count = healthcheckresultitem_set.count()
        if task_total != 0:
            progress = task_result_count / task_total
        else:
            progress = 0
        end_time = datetime.now()
        task_proxy = TaskProxy()
        if math.isclose(progress, 1.0, rel_tol=1e-5):
            task_proxy.update_task(
                task_id=self.task.task_id,
                status=TaskResultCode.SUCCESS.code,
                end_time=end_time,
                progress=progress
            )
        else:
            task_proxy.update_task(
                task_id=self.task.task_id,
                progress=progress
            )

    @staticmethod
    def batch_add_health_check_results(data, task):
        host = HostProxy().get_host_by_ip(data['host'])
        asset_proxy = AssetProxy()
        task_proxy = TaskProxy()
        for item in data['data']:
            LOGGER.info(f"{host.get('host_name')} receive {item['item_path']} result: {item['check_res']}")
            asset_item = asset_proxy.get_asset_item_by_item_path(data['assetId'], item['item_path'])
            ret = asset_proxy.add_health_check_result_item(task.task_id, host.get('host_id'), asset_item.item_id, item['check_res'])
            if ret != SUCCEED:
                LOGGER.error(f"Failed to update database data: {asset_item.item_id}")
                task_proxy.update_task(
                    task_id=task.task_id,
                    status=TaskResultCode.PARTIAL_PASSED.code
                )

    def generate_items_result(self, node_index, case_index):
        items_result_detail = self.ItemsResultDetail(self, node_index, case_index)
        items_result = items_result_detail.parse()
        return items_result

    class ItemsResultDetail:
        def __init__(self, task_result_detail, node_index, case_index):
            self._task_result_detail = task_result_detail
            self._node_index = node_index
            self._host_id = task_result_detail.task_detail['node_list'][node_index]['host_id']
            self._case_index = case_index

        def parse(self):
            items_result = list()
            chose_case_node = dict()
            for case_node in self._task_result_detail.task_detail['case_nodes']:
                if self._node_index in case_node['node_indexes']:
                    chose_case_node = case_node
            LOGGER.warning("chose_case_node: " + str(chose_case_node))
            asset_proxy = AssetProxy()
            for item_index in chose_case_node['case_indexes'][str(self._case_index)]:
                asset_item = self._task_result_detail.task_detail['case_list'][self._case_index]['asset_items'][
                    item_index]
                item_result = self.init_item_result(asset_item)
                health_check_asset_item = asset_proxy.get_asset_item_by_id(asset_item['id'])

                # 如果使用get,获取不到数据会报错,所以使用filter
                health_check_item_result = asset_proxy.get_result_item_by_id(self._task_result_detail.task.task_id, self._host_id, health_check_asset_item.item_id)

                health_check_asset_item_detail = json.loads(health_check_asset_item.item_detail)
                # 任务还没出结果
                if health_check_item_result.count() == 0:
                    items_result.append(item_result)
                    continue
                elif health_check_item_result.count() > 1:  # 存在多条结果，任务结果异常
                    item_result['status'] = TaskResultCode.FAILED.code
                    item_result['result_info']['zh'] = "该问题处理复杂，请联系华为工程师处理。"
                    item_result['result_info']['en'] = "Please contact Huawei technical support."
                    items_result.append(item_result)
                    continue

                result_list = json.loads(health_check_item_result.first().task_result)
                LOGGER.warning(f"item result code list: {result_list}")
                result = result_list[0]
                item_result['status'] = TaskResultCode.SUCCESS.code

                # 巡检项为5，表示待加固
                if result['ErrLevel'] == ItemResultCode.ITEM_RECOVER.code:
                    item_result['status'] = TaskResultCode.RECOVER.code
                # 巡检项不为0，则状态显示为失败
                elif result['ErrLevel'] != ItemResultCode.ITEM_SUCCESS.code:
                    item_result['status'] = TaskResultCode.FAILED.code
                item_result['result_info'] = self.parse_info(health_check_asset_item_detail, 'ErrInfo',
                                                             result['ErrInfo'])
                item_result['suggest'] = self.parse_info(health_check_asset_item_detail, 'Suggest', result['Suggest'])

                items_result.append(item_result)
            return items_result

        @staticmethod
        def init_item_result(asset_item):
            item_result = dict()
            item_result['check_id'] = asset_item['item_path'].split('-')[-1]
            item_result['status'] = TaskResultCode.RUNNING.code
            item_result['finished_time'] = ""
            item_result['item_name'] = asset_item['item_name']
            item_result['item_description'] = asset_item['item_description']
            item_result['result_info'] = dict()
            item_result['result_info']['zh'] = ""
            item_result['result_info']['en'] = ""
            item_result['suggest'] = dict()
            item_result['suggest']['zh'] = ""
            item_result['suggest']['en'] = ""
            return item_result

        @staticmethod
        def parse_info(health_check_asset_item_detail, tag, value):
            info = dict()
            info['zh'] = value
            info['en'] = value
            try:
                if value not in health_check_asset_item_detail[tag].keys():
                    return info
                info['zh'] = health_check_asset_item_detail[tag][value]['value_zh']['@value']
                info['en'] = health_check_asset_item_detail[tag][value]['value_en']['@value']
            except Exception as e:
                LOGGER.warning("parse_info exception, return the default result: error: %s", e)
            finally:
                return info
